use libc::{c_void,c_int, close, unshare, CLONE_NEWNET, write, CLONE_VM, CLONE_FS, CLONE_FILES, c_char};
use tokio::{select, io::{stdin, AsyncReadExt, BufReader, AsyncBufReadExt}, signal};

use crate::{sys::error::{get_last_err}, command::{cmd::Command, iptables::add_all_rules}};
use std::{fs, thread};
use std::fs::File;
use std::io::Write;


#[repr(C)]
#[derive(Clone,Debug,Default)]
pub struct SharedConfig {
    pub pipe_fds:[i32;2],
    pub ns_path:Vec<u8>,
}

pub fn new_proc(ns:String,logger:&mut File) -> Result<(),&'static str> {
    let mut fds = [0;2];
    let ret = unsafe{
        libc::pipe(fds.as_mut_ptr() as *mut c_int)
    };
    if ret == -1 {
        return Err("failed to create pipe");
    }
    let mut config = SharedConfig{
        pipe_fds:fds.clone(),
        ns_path:ns.as_bytes().to_vec(),
    };

    unsafe{
        let fd = libc::open(config.ns_path.as_ptr() as *const c_char,libc::O_RDONLY);
        if fd == -1 {
            return Err("failed to open ns file");
        }

        let res = libc::setns(fd, 0);
        if res == -1 {
            return Err("failed to enter ns");
        }
    }

    let res = add_all_rules( vec![19898i32,19800i32]);
    if let Err(e) = res {
        return Err("err res");
    }


    // let mut child_stack = [0;3*1024];
    // let ret = unsafe {
    //     libc::clone(child_fn,
    //         child_stack.as_mut_ptr().add(child_stack.len()) as *mut c_void,
    //         CLONE_FS|libc::SIGCHLD,
    //         &mut config as *mut SharedConfig as *mut c_void)
    // };
    //
    // unsafe{close(fds[0]);}

    // let wfd = fds[1].clone();
    // tokio::spawn(async move {
    //     let mut stdin_buf = BufReader::new(stdin()).lines();
        
    //     loop {
    //         select! {
    //             data = stdin_buf.next_line() => {
    //                 if let Ok(op) = data {
    //                     if let Some(in_data) = op {
    //                         if in_data.as_str() != "\n" {
    //                             let res = unsafe{write(wfd, in_data.as_ptr() as *const c_void, in_data.len())};
    //                             if res == -1 {
    //                                 println!("{}",get_last_err());
    //                                 continue;
    //                             }

    //                             if in_data.as_str() == "exit" {
    //                                 break;
    //                             }
    //                         }
    //                     }
    //                 }
    //             },
    //             _ = signal::ctrl_c() => {
    //                 let in_data = "exit";
    //                 unsafe{write(wfd, in_data.as_ptr() as *const c_void, in_data.len())};

    //                 break;
    //             }
    //         }

    //     }
    // });

    
    // let res = unsafe{libc::waitpid(ret, 0 as *mut c_int, 0)};
    // if res == -1 {
    //     let res = get_last_err();
    //     return Err(res);
    // }


    Ok(())
}


pub extern "C" fn child_fn(arg:*mut c_void) -> c_int {
    let config = unsafe {
        (&*(arg as *mut SharedConfig)).clone()
    };
    let path = String::from_utf8(config.ns_path).unwrap();

    let mut logger = fs::OpenOptions::new().write(true).create(true).open("/home/child.log").unwrap();

    unsafe{
        close(config.pipe_fds[1]);

        let fd = libc::open(path.as_ptr() as *const c_char,libc::O_RDONLY);
        if fd == -1 {
            logger.write(format!("{}\n",get_last_err()).as_bytes()).unwrap();
            return 0;
        }
        logger.write(format!("fd is :{}\n",fd).as_bytes()).unwrap();

        let res = libc::setns(fd, 0);
        if res == -1 {
            logger.write(format!("{}\n",get_last_err()).as_bytes()).unwrap();
            return 0;
        }
    }

    // let fds = config.pipe_fds[0].clone();

    let res = add_all_rules( vec![19898i32,19800i32]);
    if let Err(e) = res {
        logger.write(format!("err res :{}\n",e.to_string()).as_bytes()).unwrap();
        return 0;
    }

    // let handle = thread::spawn(move || {
    //     loop {
    //         let mut data = [0u8;500].to_vec();
    //         let res = unsafe{libc::read(fds, data.as_mut_ptr() as *mut c_void, data.len())};
    //         if res == -1 {
    //             println!("{}",get_last_err());
    //             return res as i32;
    //         }
    
    //         let mut data = String::from_utf8(data[0..res as usize].to_vec()).unwrap();
    //         if data.len() == 0 || data.as_str() == "\n" {
    //             continue;
    //         }
    //         data = data.replace("\n", "");
    
    //         match data.as_str() {
    //             "exit" => {
    //                 return 0;
    //             },
    //             d => {
    //                 let cmd = Command::new();
    //                 let res = cmd.arg(d).run();
    //                 match res {
    //                     Ok(output) => {
    //                         print!("{}\n",output);
    //                     }
    //                     Err(e) => {
    //                         println!("{}",e.to_string());
    //                     }
    //                 }
    //             }
    //         }
    //     }
    // });

    // handle.join().unwrap();

    0
}
